home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 7: Sunsite
/
Linux Cubed Series 7 - Sunsite Vol 1.iso
/
system
/
emulator
/
bsvc-1.000
/
bsvc-1
/
bsvc-1.0.4
/
src
/
SimHector
/
cpu
/
ALU.cxx
next >
Wrap
C/C++ Source or Header
|
1995-07-26
|
8KB
|
363 lines
///////////////////////////////////////////////////////////////////////////////
//
// ALU.cxx - Arithmetic Logic Unit
//
// NOTE: This code is based on the Hector simulator code written
// by Greg DeHoogh on 17 February 1990.
//
// By: Bradford W. Mott
// December 4,1993
//
///////////////////////////////////////////////////////////////////////////////
#include "ALU.hxx"
///////////////////////////////////////////////////////////////////////////////
// Compute a result with the given function and inputs
///////////////////////////////////////////////////////////////////////////////
unsigned long ALU::Compute(ALUFunction fn, unsigned long a_bus,
unsigned long b_bus)
{
unsigned long result;
switch (fn)
{
case ADD:
case ADD_NCC:
result = a_bus + b_bus;
break;
case ADDC:
if(flags & C_FLAG)
result = a_bus + b_bus + 1;
else
result = a_bus + b_bus;
break;
case SUB:
case SUB_NCC:
case CMP:
result = b_bus - a_bus;
break;
case AND:
result = a_bus & b_bus;
break;
case SUBC:
if(flags & C_FLAG)
result = b_bus - a_bus - 1;
else
result = b_bus - a_bus;
break;
case OR:
result = a_bus | b_bus;
break;
case XOR:
result = a_bus ^ b_bus;
break;
case NOT_A:
result = ~a_bus;
break;
case NEG_A:
result = -a_bus;
// Set the Carry Flag
if((result % 0x10000) == 0)
flags |= C_FLAG;
else
flags &= ~C_FLAG;
// Set the Overflow Flag
if(a_bus == 0x8000)
flags |= V_FLAG;
else
flags &= ~V_FLAG;
break;
case INC_A:
result = a_bus + 1;
// Set the Carry Flag
if((result % 0x10000) == 0)
flags |= C_FLAG;
else
flags &= ~C_FLAG;
// Set the Overflow Flag
if(a_bus == 0x8000)
flags |= V_FLAG;
else
flags &= ~V_FLAG;
break;
case INC_A_NCC:
result = a_bus + 1;
break;
case INC_B_NCC:
result = b_bus + 1;
break;
case DEC_A:
result = a_bus - 1;
// Set the Carry Flag
if(a_bus == 0)
flags |= C_FLAG;
else
flags &= ~C_FLAG;
// Set the Overflow Flag
if(a_bus == 0x8000)
flags |= V_FLAG;
else
flags &= ~V_FLAG;
break;
case DEC_A_NCC:
result = a_bus - 1;
break;
case DEC_B_NCC:
result = b_bus - 1;
break;
case SHL_A:
result = a_bus << 1;
// Set the Carry Flag
if(a_bus & 0x8000)
flags |= C_FLAG;
else
flags &= ~C_FLAG;
break;
case ROL_A:
if(flags & C_FLAG)
result = (a_bus << 1) | 1;
else
result = a_bus << 1;
// Set the Carry Flag
if(a_bus & 0x8000)
flags |= C_FLAG;
else
flags &= ~C_FLAG;
break;
case SHR_A:
result = (a_bus >> 1) | (a_bus & 0x8000);
// Set the Carry Flag
if(a_bus & 1)
flags |= C_FLAG;
else
flags &= ~C_FLAG;
break;
case ROR_A:
if(flags & C_FLAG)
result = (a_bus >> 1) | 0x8000;
else
result = a_bus >> 1;
// Set the Carry Flag
if(a_bus & 1)
flags |= C_FLAG;
else
flags &= ~C_FLAG;
break;
case BTST:
result = a_bus & b_bus;
break;
case PASS_A:
case PASS_A_NCC:
result = a_bus;
break;
case SWAP_A:
result = (a_bus >> 8) + ((a_bus & 0x00ff) << 8);
break;
case CC_OUT:
result = flags;
break;
case A_CC:
flags = a_bus & 0xf800;
result = 0;
break;
default:
result = 0;
}
/* Set the flags that were not set above */
switch (fn) {
case ADD:
case ADDC:
case SUB:
case SUBC:
case CMP:
// Set the Carry Flag
if(result > 0xffff)
flags |= C_FLAG;
else
flags &= ~C_FLAG;
// Set the Negative Flag
if(result & 0x8000)
flags |= N_FLAG;
else
flags &= ~N_FLAG;
// Set the Zero Flag
if(result & 0xffff)
flags &= ~Z_FLAG;
else
flags |= Z_FLAG;
switch (fn) {
case ADD:
case ADDC:
// Set the Overflow Flag
if (((a_bus & 0x8000) == (b_bus & 0x8000)) &&
((a_bus & 0x8000) != (result & 0x8000)))
flags |= V_FLAG;
else
flags &= ~V_FLAG;
break;
case SUB:
case SUBC:
case CMP:
// Set the Overflow flag
if (((a_bus & 0x8000) != (b_bus & 0x8000)) &&
((a_bus & 0x8000) == (result & 0x8000)))
flags |= V_FLAG;
else
flags &= ~V_FLAG;
default:
break;
}
break;
case AND:
case OR:
case XOR:
case NOT_A:
case NEG_A:
case INC_A:
case DEC_A:
case BTST:
case SWAP_A:
case SHL_A:
case ROL_A:
case SHR_A:
case ROR_A:
case PASS_A:
// Set the Negative Flag
if(result & 0x8000)
flags |= N_FLAG;
else
flags &= ~N_FLAG;
// Set the Zero Flag
if(result & 0xffff)
flags &= ~Z_FLAG;
else
flags |= Z_FLAG;
break;
default:
break;
}
return(result & 0xffff);
}
///////////////////////////////////////////////////////////////////////////////
// Test the given Condition Code and returns true if it passes
///////////////////////////////////////////////////////////////////////////////
int ALU::TestConditionCode(ALUConditionCode cc, const char* &description)
{
switch(cc)
{
case CC_VC: // overflow clear
description=".VC";
return(!(flags & V_FLAG));
case CC_PL: // plus
description=".PL";
return(!(flags & N_FLAG));
case CC_GE: // greater than or equal (signed)
description=".GE";
return(((flags & N_FLAG) && (flags & V_FLAG)) ||
(!(flags & N_FLAG) && !(flags & V_FLAG)));
case CC_F: // false
description=".F";
return 0;
case CC_LE: // less than or equal (signed)
description=".LE";
return((flags & Z_FLAG) || ((flags & N_FLAG) && !(flags & V_FLAG)) ||
(!(flags & N_FLAG) && (flags & V_FLAG)));
case CC_NE: // not equal
description=".NE";
return(!(flags & Z_FLAG));
case CC_LS: // less than or same (unsigned)
description=".LS";
return((flags & C_FLAG) || (flags & Z_FLAG));
case CC_CC: // carry clear
description=".CC";
return(!(flags & C_FLAG));
case CC_VS: // overflow set
description=".VS";
return(flags & V_FLAG);
case CC_MI: // minus
description=".MI";
return(flags & N_FLAG);
case CC_LT: // less than (signed)
description=".LT";
return(((flags & N_FLAG) && !(flags & V_FLAG)) ||
(!(flags & N_FLAG) && (flags & V_FLAG)));
case CC_T: // true
description=".T";
return 1;
case CC_GT: // greater than (signed)
description=".GT";
return(((flags & N_FLAG) && (flags & V_FLAG) && !(flags & Z_FLAG)) ||
(!(flags & N_FLAG) && !(flags & V_FLAG) && !(flags & Z_FLAG)));
case CC_EQ: // equal
description=".EQ";
return(flags & Z_FLAG);
case CC_HI: // higher (unsigned)
description=".HI";
return(!(flags & C_FLAG) && !(flags & Z_FLAG));
case CC_CS: // carry set
description=".CS";
return(flags & C_FLAG);
default:
description=".??";
return(0);
}
}